<?php

namespace Aquarii\HttpClient;

class Request implements RequestInterface
{
    protected $headers;

    protected $method;

    protected $url;

    protected $query;

    protected $body;

    const METHOD_GET = 'GET';
    const METHOD_POST = 'POST';

    /**
     * 选项用来控制一个请求(比如：PUT, POST, PATCH)的主体部分。
     *
     *  字符串/数组
     *      $client->request('PUT', '/put', ['body' => 'foo']);
     *  fopen() 打开单位文件对象
     *      $resource = fopen('http://httpbin.org', 'r');
     *      $client->request('PUT', '/put', ['body' => $resource]);
     *  二进制文件流数据
     *      $stream = GuzzleHttp\Psr7\stream_for('contents...');
     *      $client->request('POST', '/post', ['body' => $stream]);
     */
    const RAW = 'raw';

    /**
     * 用来发送一个 application/x-www-form-urlencoded POST请求
     *
     * 关联数组由表单字段键值对构成，每个字段值可以是一个字符串或一个包含字符串
     * 元素的数组。 当没有准备 "Content-Type" 报文头的时候，将设置
     * 为 "application/x-www-form-urlencoded"。
     */
    const FORM_PARAMS = 'form_params';

    /**
     * json 选项用来轻松将JSON数据当成主体上传， 如果没有设置Content-Type头
     * 信息的时候会设置成 application/json 。
     */
    const JSON = 'json';

    /**
     * 设置请求的主体为 multipart/form-data 表单。
     *
     * multipart 的值是一个关联数组，每个元素包含以下键值对：
     *  - name: (string, required) 表单字段名称
     *  - contents: (StreamInterface/resource/string, required) 表单元素中要使用的数据
     *  - headers: (array) 可选的表单元素要使用的键值对数组
     *  - filename: (string) 可选的作为要发送的文件名称
     */
    const MULTIPART = 'multipart';

    public function get(string $url, ?array $query = [])
    {
        $this->method = self::METHOD_GET;
        $this->url = $url;
        $this->query = $query;
    }

    public function post(string $url, ?mixed $body = null, string $flag = self::RAW)
    {
        $this->method = self::METHOD_POST;
        $this->url = $url;

        // 原始数据
        if ($flag == self::RAW) {
            $this->body['body'] = $body;
        }

        // 用来发送一个 application/x-www-form-urlencoded POST请求
        if ($flag == self::FORM_PARAMS) {
            $this->body['form_params'] = $body;
        }

        // 用来将 `JSON` 数据当成主体上传
        if ($flag == self::JSON) {
            $this->body['json'] = $body;
        }

        // 设置请求的主体为 multipart/form-data 表单
        if ($flag == self::MULTIPART) {
            $this->body['multipart'] = $body;
        }
    }

    public function upload(string $url, array $files, array $params = [])
    {
        $multipart = [];

        // foreach ($files as $key => $f) {
        //     $body[] = [
        //         'name' => $f['name'],
        //         'contents' => fopen($f['path'], "r"),
        //     ];
        // }

        $this->multipartAppend($multipart, $params);

        $this->post($url, $multipart, self::MULTIPART);
    }

    /**
     * 将 key=>value 参数的数据以 `multipart` 格式添加到尾部
     */
    public function multipartAppend(array &$multipart, array $params)
    {
        foreach ($params as $key => $value) {
            // set item
            $item['name'] = $key;
            $item['contents'] = $value;

            $multipart[] = $item;
        }

        return $multipart;
    }
}
